using System;
using System.Collections.Generic;
using System.Reflection;
using Infinity.Common.Extensions;

namespace Infinity.Common
{
	public class ExceptionManager : BaseExceptionManager
	{
		protected readonly Dictionary<Type, Delegate> ExceptionDictionary;
		private Delegate _DefaultExceptionHandler;

		public ExceptionManager()
		{
			ExceptionDictionary = new Dictionary<Type, Delegate>();
		}

		public ExceptionManager Catch<TException>(Action<TException> action)
		{
			Ensure.NotNull("action", action);

			if (typeof(TException) == typeof(Exception))
			{
				_DefaultExceptionHandler = action;
			}
			else if (ExceptionDictionary != null)
			{
				if (!ExceptionDictionary.ContainsKey(typeof(TException)))
					ExceptionDictionary.Add(typeof(TException), action);
				else
					ExceptionDictionary[typeof(TException)] = action;
			}

			return this;
		}

		public override void Do(Delegate action, Delegate finallyAction)
		{
			Ensure.NotNull(action);
			try
			{
				action.DynamicInvoke();
			}
			catch (TargetInvocationException ex)
			{
				if (ex.InnerException.GetType() == typeof(Exception))
				{
					if (_DefaultExceptionHandler != null)
						_DefaultExceptionHandler.DynamicInvoke(ex.InnerException);
				}											   
				else if (ExceptionDictionary != null)
				{
					if (!ExceptionDictionary.TryGetValue(ex.InnerException.GetType(),
					                                     value =>
						                                     {
							                                     if (value != null)
								                                     value.DynamicInvoke(ex.InnerException);
						                                     }))
					{
						if (_DefaultExceptionHandler != null)
							_DefaultExceptionHandler.DynamicInvoke(ex.InnerException);
					}
				}

				OnExceptionRaised(this, ex.InnerException);
			}
			finally
			{
				if (finallyAction != null)
					finallyAction.DynamicInvoke();
			}
		}
	}
}